package parser.rec;

/**
 * 递归下降分析法实现的语法分析器
 * 用于解析简单算术表达式，支持标识符(i)、加法(+)、乘法(*)及括号()
 * 语法规则:
 * E -> TE'
 * E'-> +TE' | ε
 * T -> FT'
 * T'-> *FT' | ε
 * F -> (E) | i
 */
public class RecursiveAnalysis {

    static String words = "i+i#";  // 待解析的输入字符串，以'#'作为结束符
    static int pos = 0;            // 当前字符在输入字符串中的位置索引
    static char ch = words.charAt(pos);  // 当前正在处理的字符
    static int no = 1;             // 推导步骤编号
    static String detail = "E";  // 语法推导过程的字符串表示，初始为开始符号E

    public static void main(String[] args) {
        System.out.print("E");
        exp();  // 从开始符号E开始解析
    }

    // E->TE'

    /**
     * 处理非终结符E的语法规则
     * 产生式: E -> TE'
     * 检查当前字符是否在E的First集合中( '(' 或 'i' )
     */
    static void exp() {
        if (ch == '(' || ch == 'i')// ch in first E
        {
            updateDetail((no++) + "\t" + "E->TE'");
            term();  // 解析T
            expA();  // 解析E'
        } else
            error();  // 字符不在First集合中，解析错误
    }

    // E'->+TE'|;

    /**
     * 处理非终结符E'的语法规则
     * 产生式: E' -> +TE' | ε (空串)
     * 根据当前字符选择不同产生式：'+'选择+TE'，')'或'#'选择ε
     */
    static void expA() {
        if (ch == '+') {
            updateDetail((no++) + "\t" + "E'->+TE'");
            advance();  // 消耗'+'
            term();     // 解析T
            expA();     // 递归解析E'
        } else if (ch == ')' || ch == '#')// ch in Follow expA;
        {
            updateDetail((no++) + "\t" + "E'->");  // 使用空产生式ε
            return;
        } else
            error();  // 字符不匹配，解析错误
    }

    // T->FT'

    /**
     * 处理非终结符T的语法规则
     * 产生式: T -> FT'
     * 检查当前字符是否在T的First集合中( '(' 或 'i' )
     */
    static void term() {
        if (ch == '(' || ch == 'i')// ch in first E
        {
            updateDetail((no++) + "\t" + "T->FT'");
            factor();  // 解析F
            termA();   // 解析T'
        } else
            error();  // 字符不在First集合中，解析错误
    }

    // T'->*FT'| ;

    /**
     * 处理非终结符T'的语法规则
     * 产生式: T' -> *FT' | ε (空串)
     * 根据当前字符选择不同产生式：'*'选择*FT'，')'、'#'或'+'选择ε
     */
    static void termA() {

        if (ch == '*') {
            updateDetail((no++) + "\t" + "T'->*FT'");
            advance();  // 消耗'*'
            factor();   // 解析F
            termA();    // 递归解析T'
        } else if (ch == ')' || ch == '#' || ch == '+')// ch in Follow termA;
        {
            updateDetail((no++) + "\t" + "T'->");  // 使用空产生式ε
            return;
        } else
            error();  // 字符不匹配，解析错误
    }

    // F->(E)|id

    /**
     * 处理非终结符F的语法规则
     * 产生式: F -> (E) | i (标识符)
     * 根据当前字符选择不同产生式：'('选择(E)，'i'选择i
     */
    static void factor() {
        if (ch == '(') {
            updateDetail((no++) + "\t" + "F->(E)");
            advance();  // 消耗'('
            exp();      // 解析E
            if (ch == ')')
                advance();  // 消耗')'
            else
                error();    // 缺少右括号，解析错误
        } else if (ch == 'i') {
            updateDetail((no++) + "\t" + "F->i");
            advance();  // 消耗标识符i
        } else
            error();  // 字符不匹配，解析错误
    }

    /**
     * 处理语法错误
     * 输出"ERROR"并结束解析
     */
    static void error() {
        System.out.println("ERROR");
        return;
    }

    /**
     * 移动到下一个字符
     * 若当前字符不是结束符'#'，则pos+1并更新当前字符ch
     * 若已是结束符，则调用success()表示解析成功
     */
    static void advance() {
        if (words.charAt(pos) != '#') {
            pos++;
            ch = words.charAt(pos);
        } else
            success();
    }

    /**
     * 解析成功时调用
     * 输出"SUCCESS"表示输入字符串符合语法规则
     */
    static void success() {
        System.out.println("SUCCESS");
    }

    /**
     * 辅助方法：替换字符串中第一个出现的目标子串
     *
     * @param str         原始字符串
     * @param target      要替换的目标子串
     * @param replacement 替换后的字符串
     * @return 替换后的新字符串
     */
    public static String replaceFirst(String str, String target, String replacement) {
        int index = str.indexOf(target);
        if (index == -1) {
            return str; // 未找到目标子串，返回原字符串
        }
        // 拼接替换后的字符串
        return str.substring(0, index) + replacement + str.substring(index + target.length());
    }

    /**
     * 更新语法推导过程并输出当前步骤
     *
     * @param p 格式为"步骤号\t产生式"的字符串（如"1\tE->TE'"）
     */
    static void updateDetail(String p) {
        System.out.println("\t//" + p);
        int start = p.indexOf("\t");
        int arrow = p.indexOf("->");
        String left = p.substring(start + 1, arrow);  // 产生式左部非终结符
        String right = p.substring(arrow + 2);        // 产生式右部
        detail = replaceFirst(detail, left, right);   // 更新推导字符串
        System.out.print("=>" + detail);

    }
}
